package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstant;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.listeners.message.SignInMessage;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author rui
 * @since 2024-07-29
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {
    private final StringRedisTemplate redisTemplate;

    @Override
    public void addPointsRecord(SignInMessage message,PointsRecordType type) {
        if(message == null){
            return;
        }
        log.debug("监听到的积分信息，{},{}",message,type);
        int maxPoints = type.getMaxPoints();
        int points = message.getPoints();
        //1.大于0说明积分有上限
        LocalDateTime now = LocalDateTime.now();
        Long userId = message.getUserId();
        if(maxPoints > 0){
            //1.1判断今天有没有超过限制的参数信息
            LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
            LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);

            //1.2获取今天的积分信息
            int todayPoints = getTodayPoints(dayStartTime,dayEndTime, userId,type);
            //1.3 如果超过上限 则跳过
            if(todayPoints >= maxPoints){
                return;
            }
            //1.4 如果没超过 可能有上限为20 但是今天积分17 而一次问答积分为5分，所以只能加20-17 = 3分
            if(todayPoints + message.getPoints() > maxPoints){
                points = maxPoints - todayPoints;
            }
        }
        PointsRecord record = new PointsRecord();
        record.setType(PointsRecordType.SIGN);
        record.setUserId(userId);
        record.setPoints(points);
        save(record);

        //保存redis的积分榜累加积分信息
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMM");
        String format = now.format(dateTimeFormatter);
        String boardsKey = RedisConstant.POINTS_BOARDS_KEY_PREFIX + format;
        //zSet有自带的增加函数 incrementScore
        redisTemplate.opsForZSet().incrementScore(boardsKey,userId.toString(),points);
    }

    /**
     * 查询今天的积分信息
     * @return
     */
    @Override
    public List<PointsStatisticsVO> queryTodayPoints() {
        //1.获取用户信息
        Long userId = UserContext.getUser();
        //2.封装积分类型描述，查询今天的积分类型及对应的上限
        List<PointsStatisticsVO> pointsStatisticsVOS = new ArrayList<>();
        //2.1 获取今天的参数信息
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime dayStartTime = DateUtils.getDayStartTime(now);
        LocalDateTime dayEndTime = DateUtils.getDayEndTime(now);

        //2.2 查询今日积分信息
        //select type,sum(points) from points_record where time between xxx and xxx
        // and userid = xxx
        // group by type
        QueryWrapper<PointsRecord> wrapper = new QueryWrapper<>();
        //将sum(points)信息暂时存在user_id 里
        wrapper.select("type","sum(points) as user_id");
        wrapper.eq("user_id",userId);
        wrapper.between("create_time",dayStartTime,dayEndTime);
        wrapper.groupBy("type");
        List<PointsRecord> records = this.list(wrapper);
        if(CollUtil.isEmpty(records)){
            return Collections.emptyList();
        }
        for (PointsRecord record : records) {
            if(record != null){
                PointsStatisticsVO vo = new PointsStatisticsVO();
                vo.setPoints(record.getUserId().intValue());
                vo.setMaxPoints(record.getType().getMaxPoints());
                vo.setType(record.getType().getDesc());
                pointsStatisticsVOS.add(vo);
            }
        }
        //2.3 封装返回信息
        return pointsStatisticsVOS;
    }

    private int getTodayPoints(LocalDateTime dayStartTime, LocalDateTime dayEndTime, Long userId, PointsRecordType type) {
        //1.查询今天已经获取的积分数目,可能有各种类型
        Map<String, Object> pointsMap = this.getMap(new QueryWrapper<PointsRecord>()
                .select("sum(points) as points")
                .ge("create_time", dayStartTime)
                .le("create_time", dayEndTime)
                .eq("user_id", userId)
                .eq("type",type));
        if (pointsMap == null || pointsMap.get("points") == null) {
            return 0;
        }

        // 使用BigDecimal以防止类型转换问题
        BigDecimal points = (BigDecimal) pointsMap.get("points");
        return points.intValue();
    }

}
